package service

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)


type Handler struct {
	Receiver reflect.Value  // 值
	Method   reflect.Method // 方法
	Type     reflect.Type   // 类型
	IsRawArg bool           // 数据是否需要序列化
}

type Service struct {
	Name      string              // 服务名
	Type      reflect.Type        // 服务类型
	Receiver  reflect.Value       // 服务值
	Handlers  map[string]*Handler // 注册的方法列表
	component Component
}

func NewService(comp Component) *Service {
	s := &Service{
		Type:      reflect.TypeOf(comp),
		Receiver:  reflect.ValueOf(comp),
		component: comp,
	}
	s.Name = strings.ToLower(reflect.Indirect(s.Receiver).Type().Name())
	return s
}

/**
 * 从Service中反射取出方法
 */
func (s *Service) ExtractHandler() error {
	tt := reflect.TypeOf(s.component)
	vv := reflect.ValueOf(s.component)
	serviceTypeName := reflect.Indirect(s.Receiver).Type().Name()
	if serviceTypeName == "" {
		return errors.New("no service name for type:" + s.Type.String())
	}
	//fmt.Println("reflect.ValueOf(s.component).NumField()  = ", reflect.ValueOf(s.component).NumField())
	fmt.Println("reflect.TypeOf(s.component)  = ", tt)
	fmt.Println("reflect.ValueOf(s.component)  = ", vv)
	fmt.Println("reflect.Indirect(vv).Type().Name()  = ", reflect.Indirect(vv).Type().Name())

	fmt.Println("reflect.Indirect(s.Receiver).NumField()  = ", reflect.Indirect(s.Receiver).NumField())
	fmt.Println("tt.NumMethod()  = ", tt.NumMethod())

	method := tt.Method(0)
	fmt.Println("tt.Method(0)  = ", method)
	fmt.Println("method.Type  = ", method.Type)
	fmt.Println("method.Name  = ", method.Name)
	fmt.Println("method.Type.In(0)  = ", method.Type.In(0))
	fmt.Println("method.Type.In(1)  = ", method.Type.In(1))
	//fmt.Println("vv.NumField()  = ", reflect.PtrTo(tt).NumField())

	//s.Handlers = s.suitableHandlerMethods(s.Type)

	filedNum := reflect.Indirect(s.Receiver).NumField()
	if filedNum > 0 {
		for i := 0; i < filedNum; i++ {
			tn := reflect.Indirect(s.Receiver).Field(i).Type().Name()
			fmt.Printf("i:%d, t:%s\n", i, tn)
		}
	}


	return nil
}

func (s *Service) suitableHandlerMethods(typ reflect.Type) map[string]*Handler {
	methods := make(map[string]*Handler)
	for i := 0; i < typ.NumMethod(); i++ {
		method := typ.Method(i)

		if isHandlerMethod(method) {
			mt := method.Type
			mn := strings.ToLower(method.Name)

			methods[mn] = &Handler{
				Receiver: s.Receiver,
				Method:   method,
				Type:     mt.In(2),
				IsRawArg: false,
			}
		}
	}
	return methods
}

func isHandlerMethod(m reflect.Method) bool {
	return true
}
